import requests
from faker import Faker
import logging
import os
import json
import time


def check_path(path):
	"""
	检查路径是否存在,不存在则创建
	:param path:要检测的路径
	:return:None
	"""
	# 输出目录
	os.makedirs(path, exist_ok=True)


# 检测创建log路径
check_path('log')
# 输出日志中日期格式化
FORMAT = '%(asctime)-15s  %(message)s'
# 配置日志输出
logging.basicConfig(filename='log/dl_manager.log', format=FORMAT, level=logging.DEBUG)
# 配置请求头
headers = {
	'User-Agent': Faker(locale='zh_CN').user_agent()
}
# 本地文件下载路径
local_path: str = './full'


# 设置下载路径
def config_path(path):
	global local_path
	local_path = path


# 下载器基类
class dl_base(object):
	def __init__(self, dl_urls):
		self.dl_urls = dl_urls
	
	def set_urls(self, dl_urls):
		self.dl_urls = dl_urls
	
	def dl_start(self):
		pass


# 根据任务数确认线程池线程数
def check_thread_count(lens):
	"""
	1.任务数小于20,多少任务创建多少线程
	2.超过20,每多3个任务增加1个线程
	3.最多不超过50个线程
	"""
	length = lens
	if length < 20:
		count = length
	else:
		count = 20 + int((length - 20) / 3)
	return min(count, 50)


# 根据任务数确认进程池进程数
def check_process_count(lens):
	"""
	1.任务小于10,只开2个进程
	2.任务大于10,每增加5个任务多开1个进程
	3.最多开5个进程
	"""
	length = lens
	if length < 10:
		count = 2
	else:
		count = int(length / 5)
	return min(count, 5)


# 根据任务数确认进程.线程数
def check_count(length):
	"""
	根据要下载的文件数量返回合适的进程和线程数
	:param length: 需要下载的文件数量
	:return: 包含(进程数,线程数)的元组
	"""
	if length < 1000:
		return (0, check_thread_count(length))
	else:
		return (4, check_thread_count(length))


# 同步获取数据
def get_data(url):
	"""
	根据给定url获取数据
	:param url: 指定的url
	:return: 请求结果response
	"""
	retry = 0
	resp = None
	try:
		while retry < 3:
			resp = requests.get(url, headers=headers)
			retry += 1
			if resp:
				break
		return resp
	except Exception as e:
		print('网址请求失败:{}'.format(e))
		logging.error('网址:{} |请求失败:{}'.format(url, e))
		return resp


# 分割URL获取文件类型
def get_fileInfo(url):
	"""
	根据指定的url,提取下载文件名称(带类型)
	:param url: 指定的url
	:return: 文件名称及类型
	"""
	file_name = str(url).split('/')[-1]
	return file_name


# 资源下载操作
def dl_download(url):
	"""
	根据指定url,下载并保存文件
	:param url: 指定url
	:return: None
	"""
	resp = get_data(url)
	if resp is not None:
		write_to_file(resp.content, url)
	else:
		logging.info('地址:{} : 未请求到信息'.format(url))


# 切分数组: n 切分为n个数组
def dl_list_split(items, n):
	"""
	等分切分数组
	:param items: 原始数组
	:param n: 需要切分的子数组的个数
	:return: 包含子数组的数组
	"""
	results = [[] for _ in range(n)]
	for index in range(len(items)):
		yu = index % n
		results[yu].append(items[index])
	return results


# 分组切分
# count = int(len(items) / n) + 1
# return [items[i:i + count] for i in range(0, len(items), count)]


# 根据请求的信息写入本地文件
def write_to_file(data, url):
	"""
	保存文件到本地
	:param data: 请求的文件二进制信息
	:param url: 请求文件的链接
	:return: None
	"""
	try:
		check_path(local_path)
		file_info = get_fileInfo(url)
		file_path = os.path.join(local_path, file_info)  # local_path + '/' + file_info
		with open(file_path, 'wb') as f:
			f.write(data)
		print('下载完成:{}'.format(url))
		logging.info('下载完成: {}'.format(file_path))
	except Exception as e:
		print('下载失败:{} 错误信息:{}'.format(url, e))
		logging.error('下载失败:{} 错误信息:{}'.format(url, e))


# 根据请求的信息异步写入本地文件(本想做成异步,没用到,与上重复)
def write_to_file_async(data, url):
	"""
		保存文件到本地
		:param data: 请求的文件二进制信息
		:param url: 请求文件的链接
		:return: None
		"""
	write_to_file(data, url)
